package com.example.JavaWebApi.core.mybatisplusextention;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.example.JavaWebApi.core.apiinterceptors.RequestHeaderContext;
import com.example.JavaWebApi.core.mybatisplusextention.annonation.UserId;
import com.example.JavaWebApi.core.mybatisplusextention.annonation.UserName;
import com.example.JavaWebApi.model.entity.systemEntity.Userinfo;
import lombok.SneakyThrows;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.function.Predicate;

/**
 * @program: cms_zjgs_api
 * @description: mybatisplus配置
 * @author: yang ze
 * @create: 2021-12-01 11:48
 */
@Configuration
public class MyBatisPlusConfig implements MetaObjectHandler {
    private static HashMap<String, HashMap<Field, FieldFill>> cache=new HashMap<>();
    private static Object lock=new Object();
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }

//    @Bean
//    public ConfigurationCustomizer configurationCustomizer() {
//        return configuration -> configuration.setUseDeprecatedExecutor(false);
//    }

    @SneakyThrows
    @Override
    public void insertFill(MetaObject metaObject) {
        setValue(metaObject,value->value.equals(FieldFill.INSERT)||value.equals(FieldFill.INSERT_UPDATE));
    }

    @SneakyThrows
    @Override
    public void updateFill(MetaObject metaObject) {
        setValue(metaObject,value->value.equals(FieldFill.UPDATE)||value.equals(FieldFill.INSERT_UPDATE));
    }

    private HashMap<Field, FieldFill> getCacheData(MetaObject metaObject){
        String firstKey=metaObject.getOriginalObject().getClass().getName();
        if (!cache.containsKey(firstKey)){
            synchronized (lock){
                if(!cache.containsKey(firstKey)){
                    HashMap<Field, FieldFill> fieldAndOption=new HashMap<>();
                    Arrays.stream(metaObject.getOriginalObject().getClass().getDeclaredFields()).forEach(t->{
                        if(t.isAnnotationPresent(TableField.class)){
                            TableField tableField=t.getAnnotation(TableField.class);
                            if (tableField.fill().equals(FieldFill.INSERT)||tableField.fill().equals(FieldFill.INSERT_UPDATE)||tableField.fill().equals(FieldFill.UPDATE)){
                                t.setAccessible(true);
                                fieldAndOption.put(t,tableField.fill());
                            }
                        }
                        cache.put(firstKey,fieldAndOption);
                    });
                }
            }
        }
        return cache.get(firstKey);
    }

    @SneakyThrows
    private void setValue(MetaObject metaObject, Predicate<FieldFill> predicate){
        HashMap<Field, FieldFill> fieldHash=getCacheData(metaObject);
        for(Field field:fieldHash.keySet()){
            FieldFill value=fieldHash.get(field);
            if (predicate.test(value)) {
                if (field.isAnnotationPresent(UserId.class)) {
                    Userinfo userInfo = RequestHeaderContext.getUserinfo();
                    if (userInfo != null) {
                        field.set(metaObject.getOriginalObject(), userInfo.getId());
                        continue;
                    }
                } else if (field.isAnnotationPresent(UserName.class)) {
                    Userinfo userInfo = RequestHeaderContext.getUserinfo();
                    if (userInfo != null) {
                        field.set(metaObject.getOriginalObject(), userInfo.getUserName());
                        continue;
                    }
                } else {
                    if (LocalDateTime.class.equals(field.getType())) {
                        field.set(metaObject.getOriginalObject(), LocalDateTime.now());
                        continue;
                    }
                    if (LocalDate.class.equals(field.getType())) {
                        field.set(metaObject.getOriginalObject(), LocalDate.now());
                        continue;
                    } else {
                        field.set(metaObject.getOriginalObject(), field.getType().newInstance());
                    }
                }

            }
        }
    }
}